﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
using System.Threading.Tasks;

namespace Aribaccio.Core
{
    /// <summary>
    /// 自定义服务拓展类
    /// </summary>
    public static class ServiceCollectionExtensions
    {
        /// <summary>
        /// 注册自定义内置IOC容器服务扩展
        /// </summary>
        /// <param name="argServices">内置IOC容器服务集合对象</param>
        /// <returns>内置IOC容器服务集合对象</returns>
        public static IServiceCollection RegisterServiceCustom(this IServiceCollection argServices)
        {
            List<Assembly> AssemblyList = GetAllLifeTimeAssemblies();
            if (AssemblyList != null && AssemblyList.Count() > 0)
            {
                foreach (Assembly assembly in AssemblyList)
                {
                    RegisterDependenciesByAssembly<ILifeTimeSingleton>(argServices, assembly);
                    RegisterDependenciesByAssembly<ILifeTimeTransient>(argServices, assembly);
                    RegisterDependenciesByAssembly<ILifeTimeScope>(argServices, assembly);
                }
            }
            return argServices;
        }
        /// <summary>
        /// 注册程序集组件依赖关系
        /// </summary>
        /// <typeparam name="TServiceLifetime">依赖项生命周期接口类型</typeparam>
        /// <param name="argServices">内置IOC容器服务集合对象</param>
        /// <param name="argAssembly">程序集组件对象</param>
        private static void RegisterDependenciesByAssembly<TServiceLifetime>(IServiceCollection argServices, Assembly argAssembly)
        {
            var types = argAssembly.GetTypes().Where(x => typeof(TServiceLifetime).GetTypeInfo().IsAssignableFrom(x) && x.GetTypeInfo().IsClass && !x.GetTypeInfo().IsAbstract && !x.GetTypeInfo().IsSealed).ToList();
            foreach (var type in types)
            {
                var itype = type.GetTypeInfo().GetInterfaces().FirstOrDefault(x => x.Name.ToUpper().Contains(type.Name.ToUpper()));
                if (itype != null)
                {
                    var serviceLifetime = FindServiceLifetime(typeof(TServiceLifetime));
                    argServices.Add(new ServiceDescriptor(itype, type, serviceLifetime));
                }
            }
        }
        /// <summary>
        /// 获取系统依赖项生命周期
        /// </summary>
        /// <param name="argType">依赖项生命周期服务类型</param>
        /// <returns>系统依赖项生命周期</returns>
        private static ServiceLifetime FindServiceLifetime(Type argType)
        {
            ServiceLifetime ResultLifetime = ServiceLifetime.Transient;
            if (argType == typeof(ILifeTimeSingleton))
            {
                ResultLifetime = ServiceLifetime.Singleton;
            }
            else if (argType == typeof(ILifeTimeScope))
            {
                ResultLifetime = ServiceLifetime.Scoped;
            }
            else if (argType == typeof(ILifeTimeTransient))
            {
                ResultLifetime = ServiceLifetime.Transient;
            }
            return ResultLifetime;
        }
        /// <summary>
        /// 获取所有的程序集[DI依赖注入方式]
        /// </summary>
        /// <returns>程序集集合</returns>
        private static List<Assembly> GetAllLifeTimeAssemblies()
        {
            List<Assembly> ResultAssemblyList = new List<Assembly>();
            var deps = DependencyContext.Default;
            if (deps != null)
            {
                //排除所有的系统程序集、Nuget下载包
                var libs = deps.CompileLibraries.Where(lib => !lib.Serviceable && lib.Type != "package" && lib.Type != "referenceassembly");
                foreach (var lib in libs)
                {
                    try
                    {
                        Assembly assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name));
                        if (assembly != null)
                        {
                            var serviceTypes = assembly.GetTypes().Where(x => typeof(ILifeTime).IsAssignableFrom(x) && !x.GetTypeInfo().IsAbstract);
                            if (serviceTypes != null && serviceTypes.Count() > 0)
                            {
                                ResultAssemblyList.Add(assembly);
                            }
                        }
                    }
                    catch (Exception) {/*忽略*/}
                }
            }
            return ResultAssemblyList;
        }
    }
}
